home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
DCLAP 6d
/
dclap6d
/
network
/
nsclilib
/
ni_list.c
< prev
next >
Wrap
Text File
|
1996-07-05
|
15KB
|
484 lines
/*
* ===========================================================================
*
* PUBLIC DOMAIN NOTICE
* National Center for Biotechnology Information
*
* This software/database is a "United States Government Work" under the
* terms of the United States Copyright Act. It was written as part of
* the author's official duties as a United States Government employee and
* thus cannot be copyrighted. This software/database is freely available
* to the public for use. The National Library of Medicine and the U.S.
* Government have not placed any restriction on its use or reproduction.
*
* Although all reasonable efforts have been taken to ensure the accuracy
* and reliability of the software and data, the NLM and the U.S.
* Government do not and cannot warrant the performance or results that
* may be obtained by using this software or data. The NLM and the U.S.
* Government disclaim all warranties, express or implied, including
* warranties of performance, merchantability or fitness for any particular
* purpose.
*
* Please cite the author in any work or product based on this material.
*
* ===========================================================================
*
* File Name: ni_list.c
*
* Author: Beatty, Gish
*
* Version Creation Date: 1/1/92
*
* $Revision: 4.0 $
*
* File Description:
* List and ring management functions.
*
*
* Modifications:
* --------------------------------------------------------------------------
* Date Name Description of modification
* ------- ---------- -----------------------------------------------------
* 4/23/92 Epstein Added extensive in-line commentary, and removed all tabs
* 5/11/92 Epstein Changed ListSwapAdj() to provide more rigorous testing
* that its two arguments are adjacent in the list.
* 5/14/92 Epstein Added ListStrCopy() and ListStrDel()
* 7/06/92 Epstein Fixed bug in ListStrCopy(), where the newly created
* list was not being returned to the caller ... whoops.
*
* ==========================================================================
*
*
* RCS Modification History:
* $Log: ni_list.c,v $
* Revision 4.0 1995/07/26 13:56:32 ostell
* force revision to 4.0
*
* Revision 1.2 1995/05/17 17:52:27 epstein
* add RCS log revision history
*
*/
#include "ni_list.h"
/*
* Purpose: Insert an item as the next element in a doubly linked list(ring)
*
* Parameters:
* elem Next element to be inserted; this is data only,not a NodePtr
* ap Insertion point
*
* Returns:
* The newly allocated NodePtr, containing forward and backward
* pointers and a pointer to elem
*
*
* Description:
* Allocate the necessary memory for a "Node", attach the
* caller's data to that Node, and insert the Node after the
* specified node in the list, maintaining the integrity of
* a doubly-linked ring. If there are no other items in the
* ring, create a "minimal" ring which consists of the single
* Node pointing to itself in both directions.
*
* Note:
* Most "list" data is actually stored in a doubly-linked ring, as
* shown below. Furthermore, note that each node only contains a
* pointer to the actual data in the list, rather than the actual
* data itself.
*
* +------------------------------------------------------------------+
* ^ |
* | +-------------------------------------------------------+ |
* | | ^ |
* | V | |
* | +-------+ +-------+ +-------+ | |
* | | next |------>| next |------> ... ------->| next |-->+ |
* | +-------+ +-------+ +-------+ |
* +<--| last |<------| last |<------ ... <-------| last |<-----+
* +-------+ +-------+ +-------+
* | elem | | elem | | elem |
* +-------+ +-------+ +-------+
* | | |
* | | |
* V V V
* +-------+ +-------+ +-------+
* | actual| | actual| | actual|
* | data | | data | | data |
* +-------+ +-------+ +-------+
*/
NodePtr
ListInsert(VoidPtr elem, NodePtr ap) /* ptr to node to insert after */
{
NodePtr np;
if (elem == NULL)
return NULL;
np = (NodePtr) MemNew(sizeof(Node));
np->elem = elem;
if (ap == NULL) { /* no nodes in list */
np->last = np;
np->next = np;
return np;
}
else { /* 1 or more nodes in list */
np->next = ap->next;
ap->next = np;
np->next->last = np;
np->last = ap;
return np;
}
} /* ListInsert */
/*
* Purpose: Insert an item as the previous element in a doubly linked
* list(ring)
*
* Parameters:
* elem Next element to be inserted; this is data only,not a NodePtr
* ap Insertion point
*
* Returns:
* The newly allocated NodePtr, containing forward and backward
* pointers and a pointer to elem
*
*
* Description:
* Insert the specified item into the ring, before the specified
* insertion point. In the case where the specified insertion
* point was NULL, this is equivalent to ListInsert().
*/
NodePtr
ListInsertPrev(VoidPtr elem, NodePtr ap) /* ptr to node to insert before */
{
NodePtr np;
np = ap;
if (ap != NULL)
ap = ap->last; /* previous node */
ap = ListInsert(elem, ap);
return (np == NULL) ? ap : np;
} /* ListInsertPrev */
/*
* Purpose: Delete a single node from a list or ring
*
* Parameters:
* np Node to be deleted
*
* Returns:
* A pointer to the "next" node in the list/ring, after the
* deleted node.
*
*
* Description:
* Delete the specified node from a list or ring. It is the
* responsibility of the caller to free the memory associated
* with the "elem" (data), if appropriate.
*/
NodePtr
ListDelete(NodePtr np)
{
NodePtr nextnode, lastnode;
if (np == NULL)
return NULL;
nextnode = np->next;
lastnode = np->last;
if (nextnode == NULL && lastnode == NULL) /* only node in a list */
;
else if (nextnode == NULL) { /* last in a list */
np->last->next = NULL;
nextnode = np->last;
}
else if (lastnode == NULL) { /* first in a list */
np->next->last = NULL;
nextnode = np->next;
}
else if (np == nextnode) /* last in a ring */
nextnode = NULL;
else { /* node with both neighbors */
np->last->next = nextnode;
np->next->last = np->last;
}
MemFree(np); /* assumes element memory has been freed */
return nextnode;
} /* ListDelete */
/*
* Purpose: Get the next element from a list or ring (non-destructively)
*
* Parameters:
* np Node before the node to be selected
*
* Returns:
* A pointer to the "next" node in the list/ring (or NULL
* if the list/ring was NULL). Note that for a list, the
* returned value can also be NULL.
*
*
* Description:
* Return the "next" node in the list or rin.g
*/
NodePtr
ListGetNext(NodePtr np)
{
if (np == NULL)
return NULL;
return np->next;
} /* ListGetNext */
/*
* Purpose: Swap two adjacent nodes in a list or ring
*
* Parameters:
* np1 "Prior" node
* np2 "Next" node
*
*
* Description:
* Swap the two specified elements, provided that they are
* adjacent, and np1 precedes np2.
*/
void
ListSwapAdj(NodePtr np1, NodePtr np2) /* priornode, nextnode */
{
if (np1 == NULL || np2 == NULL || np1->next->last != np1) /* must be sane */
return;
if (np1->next != np2 || np2->last != np1) /* must be in order */
return;
if (np1->last != NULL)
np1->last->next = np2;
if (np2->next != NULL)
np2->next->last = np1;
np1->next = np2->next;
np2->last = np1->last;
np1->last = np2;
np2->next = np1;
} /* ListSwapAdj */
/*
* Purpose: Sort the specified ring/list
*
* Parameters:
* head Head of the list to be sorted
* cmpfunc Comparison function (return values are like memcmp())
* order ASCEND or DESCEND
*
* Returns:
* A pointer to the first element of the sorted ring or list
*
*
* Description:
* Sort the specified list, in place, using bubble sort, and
* the specified comparison function. Determine prior to sorting
* whether this is a list or a ring. If it's a ring, break the
* ring prior to sorting, and restore it to a ring topology
* after sorting has been completed.
*/
NodePtr
ListSort(NodePtr head, int (*cmpfunc )PROTO ((NodePtr, NodePtr )), int order) /* 0 if equal, LT 0 if 1st element > 2nd element */
{
NodePtr np;
Boolean sorted = FALSE, ring;
int result;
if (head == NULL)
return NULL;
if (head->last == NULL)
ring = FALSE;
else
ring = TRUE;
if (ring)
ListBreakRing(head);
/* just bubble sort for now */
while (! sorted) {
np = head;
sorted = TRUE;
while (np->next != NULL) {
result = (*cmpfunc)(np, np->next);
if ((result > 0 && order == ASCEND) || (result < 0 && order == DESCEND)) {
sorted = FALSE;
if (np == head)
head = np->next; /* keep head pointing at 1st element */
ListSwapAdj(np, np->next);
}
else
np = np->next;
}
}
if (ring)
ListConnectRing(head);
return head; /* ptr to first element */
} /* ListSort */
/*
* Purpose: Break the specified ring into a non-circular (linear) list
*
* Parameters:
* np Head of the ring to be broken
*
*
* Description:
* Break the specified ring between its head and tail.
*
* Note:
* This function may be called safely (without effect) if the
* passed parameter is already a list, rather than a ring.
*/
void
ListBreakRing(NodePtr np)
{
if (np == NULL)
return;
if (np->last == NULL)
return;
np->last->next = NULL;
np->last = NULL;
} /* ListBreakRing */
/*
* Purpose: Convert a list into a ring.
*
* Parameters:
* head Head of the list to be connected
*
*
* Description:
* Connect the specified list between its head and tail, producing
* a ring.
*
* Note:
* This function may be called safely (without effect) if the
* passed parameter is already a ring, rather than a list.
*/
void
ListConnectRing(NodePtr head)
{
NodePtr np;
if (head == NULL)
return;
np = head;
while (np->next != NULL) {
np = np->next;
if (np == head)
return;
}
np->next = head;
head->last = np;
} /* ListConnectRing */
/*
* Purpose: Copy a list where the list elements are character strings
*
* Parameters:
* strlist List to be copied
*
* Returns:
* A copy of the original list (which may be NULL)
*
*
* Description:
* Create a list which is a copy of the original list, and
* also make copies of the strings.
*
* Note:
* There is no obvious way to make a generic list copying
* routine, because, in general, the length of each list
* element is unknown. This is a simple case where it is
* easy to copy a list.
*/
NodePtr
ListStrCopy (NodePtr strlist)
{
NodePtr newlist = NULL;
NodePtr np = strlist;
CharPtr stringtext;
if (strlist == NULL)
return NULL;
do {
stringtext = StringSave((CharPtr) np->elem);
newlist = ListInsert(stringtext, newlist);
np = ListGetNext(np);
} while (np != NULL && np != strlist);
return newlist->next; /* points to 1st element in new list */
}
/*
* Purpose: Delete a list where the list elements are character strings
*
* Parameters:
* np List to be deleted
*
*
* Description:
* Delete the list nodes and the character string data associated
* with each node.
*
* Note:
* This routine will work for any list element which is a single
* block of memory. However, it will not work in the more general
* case where a list element in turn references other memory
* which must also be freed.
*/
void
ListStrDel (NodePtr np)
{
while (np != NULL)
{
MemFree (np->elem);
np = ListDelete(np);
}
}